// Texas A&M University          //
// cpsc350 Computer Architecture //
// $Id: SingleCycleProc.v,v 1.1 2002/04/08 23:16:14 miket Exp miket $ //

// Top Level Architecture Model //

`include "IdealMemory.v"
`include "registers32_32.v"
`include "extender.v"
`include "pc.v"
`include "control_sig.v"

/*-------------------------- CPU -------------------------------
 * This module implements a single-cycle
 * CPU similar to that described in the text book 
 * (for example, see Figure 5.19). 
 *
 */

//
// Input Ports
// -----------
// clock - the system clock (m555 timer).
//
// reset - when asserted by the test module, forces the processor to 
//         perform a "reset" operation.  (note: to reset the processor
//         the reset input must be held asserted across a 
//         negative clock edge).
//   
//         During a reset, the processor loads an externally supplied
//         value into the program counter (see startPC below).
//   
// startPC - during a reset, becomes the new contents of the program counter
//	     (starting address of test program).
// 
// Output Port
// -----------
// dmemOut - contains the data word read out from data memory. This is used
//           by the test module to verify the correctness of program 
//           execution.
//-------------------------------------------------------------------------

module SingleCycleProc(CLK, Reset_L, startPC, dmemOut);
   input 	Reset_L, CLK;
   input [31:0] startPC;
   output [31:0] dmemOut;
   wire [31:0] immed16_ext,dataB,Mem_DOUT,Result,busA,
			   busB, busW, immed16_fetchExt,add1,add2,PCin,toPC, instrAddr,
			   Instruction;
   // Control signals
   wire Zero, nPC_sel, RegWr,RegDst,ExtOp,ALUSrc,MemWr,MemtoReg,Jump;
   wire [1:0] ShiftSig;
   wire [4:0] Rw;
   wire [3:0] ALUctr;
   
//
// INSERT YOUR CPU MODULES HERE
//
//this is the main cpu cycle
control_sig Controller(startPC, Zero, nPC_sel, RegWr,RegDst,ExtOp,ALUSrc,ALUctr,MemWr,MemtoReg,ShiftSig,Jump);
MUX5_2to1 f0 (startPC[15:11], start[20:16], RegDst, Rw);
registers32_32 s0 (Rw,startPC[25:21],startPC[20:16],RegWr,CLK,busW,busA,busB);

extender_16to32 s1 (startPC[15:0],immed16_ext);
MUX32_2to1 ALUorImmediate(busB,immed16_ext,ALUSrc,dataB);
ALU_behav ALU(busA, dataB, ALUctr, Result, , 0, , Zero );
DataMem mainMemory(Result,CLK,~MemWr,MemWr,busB,Mem_DOUT);
MUX32_2to1 MemOrReg (Result,Mem_DOUT,MemtoReg,busW);

// Using the instruction, determine the control signals
// SIGNATURE HAS CHANGED!  this is not up to date


// Fetch the next instruction
FetchUnit instrFetch (nPC_sel, Jump, startPC[15:0], startPC[25:0], startPC,CLK);

//
// Debugging threads that you may find helpful (you may have
// to change the variable names).
//
   /*  Monitor changes in the program counter
   always @(PC)
     #10 $display($time," PC=%d Instr: op=%d rs=%d rt=%d rd=%d imm16=%d funct=%d",
	PC,Instr[31:26],Instr[25:21],Instr[20:16],Instr[15:11],Instr[15:0],Instr[5:0]);
   */

   /*   Monitors memory writes
   always @(MemWrite)
	begin
	#1 $display($time," MemWrite=%b clock=%d addr=%d data=%d", 
	            MemWrite, clock, dmemaddr, rportb);
	end
   */
   
endmodule // CPU


module m555 (CLK);
   parameter StartTime = 0, Ton = 50, Toff = 50, Tcc = Ton+Toff; // 
 
   output CLK;
   reg 	  CLK;
   
   initial begin
      #StartTime CLK = 0;
   end
   
   // The following is correct if clock starts at LOW level at StartTime //
   always begin
      #Toff CLK = ~CLK;
      #Ton CLK = ~CLK;
   end
endmodule

   
module testCPU(Reset_L, startPC, testData);
   input [31:0] testData;
   output 	Reset_L;
   output [31:0] startPC;
   reg 		 Reset_L;
   reg [31:0] 	 startPC;
   
   initial begin
      // Your program 1
      Reset_L = 0;  startPC = 0 * 4;
      #101 // insures reset is asserted across negative clock edge
	  Reset_L = 1; 
      #10000; // allow enough time for program 1 to run to completion
      Reset_L = 0;
      #1 $display ("Program 1: Result: %d", testData);
      
      // Your program 2
      startPC = 14 * 4;
      #101 Reset_L = 1; 
      #10000;
      Reset_L = 0;

      #1 $display ("Program 2: Result: %d", testData);
      
      // etc.
      // Run other programs here
      
      
      $finish;
   end endmodule // testCPU

module TopProcessor;
   wire reset, CLK, Reset_L;
   wire [31:0] startPC;
   wire [31:0] testData;
   
   m555 system_clock(CLK);
   SingleCycleProc SSProc(CLK, Reset_L, startPC, testData);
   testCPU tcpu(Reset_L, startPC, testData); 

endmodule // TopProcessor
